package com.ruoyi.plus.utils.aliyunoss;


import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.ObjectMetadata;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;

/**
 * oss对象存储服务minio工具类
 *
 * @author likun
 */
@Slf4j
@Component
public class AliyunOssUtils {


    public static OSSClient ossClient;
    public static AliyunOssUtils aliyunOssUtils;
    public static AliyunOssProperties config;

    @Autowired
    private AliyunOssProperties aliyunOssProperties;


    /**
     * 文件上传 （返回URL下载地址）
     *
     * @param file 文件
     * @return: 文件url下载地址
     */
    @SneakyThrows(Exception.class)
    public static String uploadFile(MultipartFile file) {
        final String fileName = FileUploadUtils.extractFilename(file);
        return uploadFile(file, fileName);
    }

    /**
     * 文件上传 （返回URL下载地址）
     *
     * @param file 文件
     * @return: 文件url下载地址
     */
    @SneakyThrows(Exception.class)
    public static String uploadFile(MultipartFile file, String fileName) {
        fileName = filterFileName(fileName);
        final InputStream is = file.getInputStream();
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
        ossClient.putObject(config.getBucketName(), fileName, is, metadata);
        is.close();
        return getFileUrl(config.getBucketName(), fileName);
    }

    /**
     * 文件上传 （返回URL下载地址）
     *
     * @param stream   文件
     * @param fileName 文件名(fileName需带后缀，minio根据后缀推断类型)
     * @return: 文件url下载地址
     */
    @SneakyThrows(Exception.class)
    public static String uploadStream(InputStream stream, String fileName) {
        fileName = filterFileName(fileName);
        File file = new File(fileName);
        FileUtils.copyToFile(stream, file);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
        ossClient.putObject(config.getBucketName(), fileName, stream, metadata);
        file.delete();
        return getFileUrl(config.getBucketName(), fileName);
    }

    /**
     * 文件上传 （返回URL下载地址）
     *
     * @param stream      文件
     * @param fileName    文件名(fileName需带后缀)
     * @param contentType 文件类型
     * @return: 文件url下载地址
     */
    @SneakyThrows(Exception.class)
    public static String uploadStream(InputStream stream, String fileName, String contentType) {
        fileName = filterFileName(fileName);
        File file = new File(fileName);
        FileUtils.copyToFile(stream, file);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
        ossClient.putObject(config.getBucketName(), fileName, stream, metadata);
        file.delete();
        return getFileUrl(config.getBucketName(), fileName);
    }


    /**
     * 文件上传 （返回URL下载地址）
     *
     * @param file 文件
     * @return: 文件url下载地址
     */
    @SneakyThrows(Exception.class)
    public static String uploadFile(File file) {
        if (!file.exists()) {
            return null;
        }
        String fileName = DateUtils.datePath() + "/" + file.getName();
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
        ossClient.putObject(config.getBucketName(), fileName, file, metadata);
        return getFileUrl(config.getBucketName(), fileName);
    }

    /**
     * 删除默认桶内的指定文件
     *
     * @param fileName 文件名
     */
    @SneakyThrows(Exception.class)
    public static void deleteFile(String fileName) {
        fileName = filterFileName(fileName);
        ossClient.deleteObject(config.getBucketName(), fileName);
    }


    /**
     * 判断 bucket是否存在
     *
     * @param bucketName 桶名
     * @return: boolean
     */
    @SneakyThrows(Exception.class)
    public static boolean bucketExists(String bucketName) {
        return ossClient.doesBucketExist(bucketName);
    }

    /**
     * 创建 bucket
     *
     * @param bucketName 桶名
     * @return: void
     */
    @SneakyThrows(Exception.class)
    public static void createBucket(String bucketName) {
        boolean isExist = ossClient.doesBucketExist(bucketName);
        if (!isExist) {
            ossClient.createBucket(bucketName);
        }
    }

    /**
     * 获取全部bucket
     *
     * @return: java.util.List<io.minio.messages.Bucket>
     */
    @SneakyThrows(Exception.class)
    public static List<Bucket> getAllBuckets() {
        return ossClient.listBuckets();
    }


    /**
     * 文件上传（返回URL下载地址）
     *
     * @param bucketName 桶名
     * @param fileName   文件名
     * @param stream     文件流
     * @return: 文件url下载地址
     */
    @SneakyThrows(Exception.class)
    public static String upload(String bucketName, String fileName, InputStream stream) {
        fileName = filterFileName(fileName);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
        ossClient.putObject(bucketName, fileName, stream, metadata);
        return getFileUrl(bucketName, fileName);
    }

    /**
     * 文件上传 （返回URL下载地址）
     *
     * @param bucketName 桶名
     * @param file       文件
     * @return: 文件url下载地址
     */
    @SneakyThrows(Exception.class)
    public static String upload(String bucketName, MultipartFile file) {
        final InputStream is = file.getInputStream();
        final String fileName = file.getOriginalFilename();
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
        ossClient.putObject(bucketName, fileName, is, metadata);
        is.close();
        return getFileUrl(bucketName, fileName);
    }


    /**
     * 删除文件
     *
     * @param bucketName 桶名
     * @param fileName   文件名
     */
    @SneakyThrows(Exception.class)
    public static void deleteFile(String bucketName, String fileName) {
        fileName = filterFileName(fileName);
        ossClient.deleteObject(bucketName, fileName);
    }

    /**
     * 下载文件 （流输出）
     *
     * @param bucketName 桶名
     * @param fileName   文件名
     */
    @SneakyThrows(Exception.class)
    public static void download(String bucketName, String fileName, HttpServletResponse response) {
        fileName = filterFileName(fileName);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        InputStream is = ossClient.getObject(bucketName, fileName).getObjectContent();
        IOUtils.copy(is, response.getOutputStream());
        is.close();
    }

    /**
     * 获取minio文件的下载地址
     *
     * @param bucketName 桶名
     * @param fileName   文件名
     */
    @SneakyThrows(Exception.class)
    public static String getFileUrl(String bucketName, String fileName) {
        //return minioClient.presignedGetObject(bucketName, fileName);
        //return minioClient.getObjectUrl(bucketName, fileName).replace(minioConfig.getApiUrl(), minioConfig.getViewUrl());
        String url = config.getViewUrl() + "/" + fileName;
        log.info(url);
        return url;
    }

    @SneakyThrows(Exception.class)
    public static String filterFileName(String fileName) {
        if (fileName != null) {
            fileName = fileName.replace(config.getViewUrl() + "/" + config.getBucketName() + "/", "");
            if (fileName.toLowerCase().contains("/oss-")) {
                fileName = fileName.substring(fileName.toLowerCase().indexOf("/oss-") + 1);
                fileName = fileName.substring(fileName.indexOf("/") + 1);
            }
            return fileName;
        }
        return "";
    }

    @SneakyThrows(Exception.class)
    public static String getContentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".pdf")) {
            return "application/pdf";
        }
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "image/jpg";
    }

    /**
     * 初始化minio配置
     */
    @PostConstruct
    public void init() {
        if (this.aliyunOssProperties != null) {
            config = aliyunOssProperties;
            if (this.aliyunOssProperties.isEnabled()) {
                log.info(">>>>>>>>>>>aliyunOss 初始化开始");
                aliyunOssUtils = this;
                aliyunOssUtils.aliyunOssProperties = this.aliyunOssProperties;
                try {
                    ossClient = new OSSClient(aliyunOssProperties.getEndPoint(), aliyunOssProperties.getAccessKey(), aliyunOssProperties.getSecretKey());
                    log.info(">>>>>>>>>>>aliyunOss 初始化成功!");
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("》》》》》》》》》》初始化aliyunOss异常: 【{}】", e.fillInStackTrace());
                }
            }
        }

    }


}
